﻿// --------------------------------------------------------------------------------------------------------------------
// <copyright file="AutoUpdater.cs" company="StyleCop for ReSharper Development Team">
//   Copyright (c) StyleCop for ReSharper Development Team. All rights reserved.
// </copyright>
// <summary>
//   Defines the AutoUpdater type.
// </summary>
// --------------------------------------------------------------------------------------------------------------------

namespace StyleCop.For.ReSharper
{
    #region Using Directives

    using System;
    using System.Diagnostics;
    using System.Net;
    using System.Windows.Forms;

    using JetBrains.Application;
    using JetBrains.ComponentModel;

    using StyleCop.For.ReSharper.Diagnostics;
    using StyleCop.For.ReSharper.Options;

    #endregion

    /// <summary>
    /// Provides automatic updating functionality for the plugin.
    /// </summary>
    [ShellComponentImplementation(ProgramConfigurations.ALL)]
    public class AutoUpdater : IShellComponent
    {
        #region Constants and Fields

        /// <summary>
        /// Message box title.
        /// </summary>
        private const string MessageBoxTitle = "StyleCop for ReSharper";

        /// <summary>
        /// Question text.
        /// </summary>
        private const string QuestionText =
            "Version {1} of this plugin is now available.\r\nYou currently have version {0}.\r\n\r\nOnce downloaded and installed you'll need to restart Visual Studio.\r\n\r\nDo you wish to download the latest version?";

        /// <summary>
        /// Version url.
        /// </summary>
        private const string VersionUrl = "http://resharperstylecop.com/release/4.5/version.txt";

        #endregion

        #region Implemented Interfaces

        #region IComponent

        /// <summary>
        /// Initialises this IShellComponent.
        /// </summary>
        public void Init()
        {
            StyleCopTrace.In();

            if (StyleCopOptions.Instance.AutomaticallyCheckForUpdates)
            {
                var lastUpdateCheckDate = DateTime.Parse(StyleCopOptions.Instance.LastUpdateCheckDate);
                var daysBetweenUpdateChecks = StyleCopOptions.Instance.DaysBetweenUpdateChecks;

                if (StyleCopOptions.Instance.AlwaysCheckForUpdatesWhenVisualStudioStarts || DateTime.UtcNow > lastUpdateCheckDate.AddDays(daysBetweenUpdateChecks))
                {
                    var client = new WebClient();
                    client.DownloadStringCompleted += this.DownloadStringCompleted;
                    client.DownloadStringAsync(new Uri(VersionUrl));
                }
            }

            StyleCopTrace.Out();
        }

        #endregion

        #region IDisposable

        /// <summary>
        /// An empty Dispose method.
        /// </summary>
        public void Dispose()
        {
            // Nothing in here
        }

        #endregion

        #endregion

        #region Methods

        /// <summary>
        /// Get new version information.
        /// </summary>
        /// <param name="result">
        /// The result.
        /// </param>
        /// <param name="currentVersionNUmber">
        /// The current version number.
        /// </param>
        /// <param name="newVersionNumber">
        /// The new version number.
        /// </param>
        /// <param name="newVersionUri">
        /// The new version uri.
        /// </param>
        /// <param name="messageText">
        /// The message text.
        /// </param>
        /// <returns>
        /// The get new version information.
        /// </returns>
        private static bool GetNewVersionInformation(string result, Version currentVersionNUmber, out Version newVersionNumber, out string newVersionUri, out string messageText)
        {
            messageText = String.Empty;
            newVersionUri = String.Empty;

            var newVersionArray = result.Split(new[] { "\r", "\n" }, StringSplitOptions.RemoveEmptyEntries);
            newVersionNumber = new Version(String.Format("{0}.{1}.{2}.{3}", newVersionArray[0], newVersionArray[1], newVersionArray[2], newVersionArray[3]));

            if (newVersionArray.Length > 4)
            {
                newVersionUri = newVersionArray[4];
            }

            if (newVersionArray.Length > 5)
            {
                messageText = newVersionArray[5];
            }

            return newVersionNumber.CompareTo(currentVersionNUmber) > 0;
        }

        /// <summary>
        /// Prompt user for download.
        /// </summary>
        /// <param name="currentVersionNumber">
        /// The current version number.
        /// </param>
        /// <param name="newVersionNumber">
        /// The new version number.
        /// </param>
        /// <param name="messageText">
        /// The message text.
        /// </param>
        /// <returns>
        /// The prompt user for download.
        /// </returns>
        private static bool PromptUserForDownload(string currentVersionNumber, string newVersionNumber, string messageText)
        {
            if (string.IsNullOrEmpty(messageText))
            {
                return MessageBox.Show(String.Format(QuestionText, currentVersionNumber, newVersionNumber), MessageBoxTitle, MessageBoxButtons.YesNo) == DialogResult.Yes;
            }

            MessageBox.Show(messageText, MessageBoxTitle, MessageBoxButtons.OK);
            return false;
        }

        #endregion

        #region Event Handlers

        /// <summary>
        /// Download string completed.
        /// </summary>
        /// <param name="sender">
        /// The sender.
        /// </param>
        /// <param name="e">
        /// The e.
        /// </param>
        private void DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
        {
            try
            {
                string newVersionUri;
                Version newVersionNumber;
                string messageText;

                if (e.Error != null)
                {
                    return;
                }

                if (!StyleCopOptions.Instance.AlwaysCheckForUpdatesWhenVisualStudioStarts)
                {
                    StyleCopOptions.Instance.LastUpdateCheckDate = DateTime.UtcNow.ToString("yyyy-MM-dd");
                }

                var currentVersionNumber = this.GetType().Assembly.GetName().Version;
                var newerPlugInAvailable = GetNewVersionInformation(e.Result, currentVersionNumber, out newVersionNumber, out newVersionUri, out messageText);

                if (newerPlugInAvailable && PromptUserForDownload(currentVersionNumber.ToString(), newVersionNumber.ToString(), messageText))
                {
                    // this will launch the default browser at the download url
                    Process.Start(newVersionUri);
                }
            }
            catch
            {
                // if anything at all goes wrong in here we just consume it and say nothing
                return;
            }
        }

        #endregion
    }
}